#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import os
import struct
import argparse
import re
from elftools.elf.elffile import ELFFile
from elftools.dwarf.descriptions import describe_form_class
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB
import subprocess
# 常量定义
REGISTERS = [
    'R0',  'R1',  'R2',  'R3',     # 参数传递和临时值
    'R4',  'R5',  'R6',  'R7',     # 局部变量
    'R8',  'R9',  'R10', 'R11',    # 局部变量
    'R12',                         # IP(Inter-Procedure call)
    'SP',                          # R13 - 栈指针
    'LR',                          # R14 - 链接寄存器
    'PC'                           # R15 - 程序计数器
]

SPECIAL_REGISTERS = [
    'xPSR',    # 程序状态寄存器(包含APSR/IPSR/EPSR)
    'CFBP',    # 控制寄存器组合(CONTROL/FAULTMASK/BASEPRI/PRIMASK)
    'MSP',     # 主栈指针
    'PSP',     # 进程栈指针
]

FAULT_REGISTERS = [
    'CFSR',    # 可配置故障状态寄存器
    'HFSR',    # 硬故障状态寄存器
    'DFSR',    # 调试故障状态寄存器
    'MMFAR',   # 存储器管理故障地址寄存器
    'BFAR',    # 总线故障地址寄存器
    'AFSR'     # 辅助故障状态寄存器
]

class StackTracer(object):
    def __init__(self, axf_path, ram_dump_path, reg_dump_path=None, map_path=None):
        # 基础配置
        self.registers = {}  # 寄存器值
        self.memory_regions = {}  # 内存区域信息
        self.section_layout = {}  # 段布局
        self.map_symbols = {}  # MAP文件中的符号信息
        self.symbols = {}  # AXF文件中的符号信息
        
        # 加载AXF文件
        self.AXF = axf_path
        self._axf = open(axf_path, 'rb')
        self.elf = ELFFile(self._axf)
        
        # 加载RAM dump
        with open(ram_dump_path, 'rb') as f:
            self.ram_data = f.read()
            
        # 加载寄存器值
        if reg_dump_path:
            self.load_registers(reg_dump_path)
            
        # 加载MAP文件
        if map_path:
            self.load_map_file(map_path)
            
        # 初始化反汇编引擎
        self.cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
        self.cs.detail = True
        
        # 加载符号
        self.load_symbols()

    def __del__(self):
        """清理资源"""
        if hasattr(self, '_axf'):
            self._axf.close()
    def load_registers_from_text(self, text):
        """从文本解析寄存器值"""
        register_patterns = {
            'PC': r'PC\s*=\s*([0-9A-Fa-f]{8})',
            'LR': r'R14\(LR\)\s*=\s*([0-9A-Fa-f]{8})',
            'SP': r'SP\(R13\)\s*=\s*([0-9A-Fa-f]{8})',
            'MSP': r'MSP\s*=\s*([0-9A-Fa-f]{8})',
            'PSP': r'PSP\s*=\s*([0-9A-Fa-f]{8})',
            'XPSR': r'XPSR\s*=\s*([0-9A-Fa-f]{8})',
            'CFBP': r'CFBP\s*=\s*([0-9A-Fa-f]{8})',
            'CFSR': r'CFSR\s*=\s*([0-9A-Fa-f]{8})',
            'HFSR': r'HFSR\s*=\s*([0-9A-Fa-f]{8})',
            'MMFAR': r'MMFAR\s*=\s*([0-9A-Fa-f]{8})',
            'BFAR': r'BFAR\s*=\s*([0-9A-Fa-f]{8})'
        }
        
        # 添加R0-R12的模式
        for i in range(13):
            register_patterns['R%d' % i] = r'R%d\s*=\s*([0-9A-Fa-f]{8})' % i

        for reg, pattern in register_patterns.items():
            match = re.search(pattern, text)
            if match:
                self.registers[reg] = int(match.group(1), 16)

    def load_registers(self, reg_path):
        """加载寄存器文件"""
        try:
            with open(reg_path, 'r') as f:
                content = f.read()
                self.load_registers_from_text(content)
                self.parse_special_registers()
        except Exception as e:
            print("Warning: Failed to load registers:", str(e))

    def parse_special_registers(self):
        """解析特殊寄存器的位域"""
        if 'XPSR' in self.registers:
            xpsr = self.registers['XPSR']
            self.registers.update({
                'IPSR': xpsr & 0x1FF,          # 异常号
                'EPSR': (xpsr >> 16) & 0xFF,   # 执行状态
                'APSR_N': (xpsr >> 31) & 1,    # 负标志
                'APSR_Z': (xpsr >> 30) & 1,    # 零标志
                'APSR_C': (xpsr >> 29) & 1,    # 进位标志
                'APSR_V': (xpsr >> 28) & 1,    # 溢出标志
                'APSR_Q': (xpsr >> 27) & 1     # 饱和标志
            })

        if 'CFBP' in self.registers:
            cfbp = self.registers['CFBP']
            self.registers.update({
                'CONTROL': cfbp & 0xFF,
                'FAULTMASK': (cfbp >> 8) & 0xFF,
                'BASEPRI': (cfbp >> 16) & 0xFF,
                'PRIMASK': (cfbp >> 24) & 0xFF
            })

    def print_registers(self):
        """打印寄存器状态"""
        print("\n=== Register State ===")
        
        # 打印通用寄存器
        for i in range(0, len(REGISTERS), 4):
            regs = REGISTERS[i:i+4]
            values = []
            for reg in regs:
                val = self.registers.get(reg, 0)
                values.append("{:3}: 0x{:08X}".format(reg, val))
            print("    ".join(values))
            
        # 打印特殊寄存器
        print("\n=== Special Registers ===")
        if 'XPSR' in self.registers:
            xpsr = self.registers['XPSR']
            print("xPSR  : 0x{:08X}".format(xpsr))
            print("  IPSR: {} ({})".format(
                self.registers.get('IPSR', 0),
                "HardFault" if self.registers.get('IPSR', 0) == 3 else "Unknown"
            ))
            print("  APSR: N={} Z={} C={} V={} Q={}".format(
                self.registers.get('APSR_N', 0),
                self.registers.get('APSR_Z', 0),
                self.registers.get('APSR_C', 0),
                self.registers.get('APSR_V', 0),
                self.registers.get('APSR_Q', 0)
            ))
            
        if 'CFBP' in self.registers:
            print("\nControl Registers:")
            print("  CONTROL  : 0x{:02X}".format(self.registers.get('CONTROL', 0)))
            print("  PRIMASK  : 0x{:02X}".format(self.registers.get('PRIMASK', 0)))
            print("  BASEPRI  : 0x{:02X}".format(self.registers.get('BASEPRI', 0)))
            print("  FAULTMASK: 0x{:02X}".format(self.registers.get('FAULTMASK', 0)))
    def load_map_file(self, map_path):
        """解析MAP文件"""
        current_section = None
        try:
            with open(map_path, 'r') as f:
                lines = f.readlines()
                
            for line in lines:
                line = line.strip()
                
                # 解析内存区域
                if 'Memory Configuration' in line:
                    current_section = 'memory'
                    continue
                elif 'Linker script and memory map' in line:
                    current_section = 'layout'
                    continue
                    
                # 跳过空行
                if not line:
                    continue
                    
                if current_section == 'memory':
                    # 解析内存区域行: "RAM      0x20000000      0x00020000"
                    parts = line.split()
                    if len(parts) >= 3 and not line.startswith('.'):
                        name = parts[0]
                        try:
                            start = int(parts[1], 16)
                            size = int(parts[2], 16)
                            self.memory_regions[name] = {
                                'start': start,
                                'size': size,
                                'end': start + size
                            }
                        except ValueError:
                            continue
                            
                elif current_section == 'layout':
                    # 解析section和符号定义
                    if line.startswith('.'):
                        # 段定义行: ".text 0x08000000"
                        parts = line.split()
                        if len(parts) >= 2:
                            try:
                                addr = int(parts[-1], 16)
                                name = ' '.join(parts[:-1])
                                self.section_layout[name] = {
                                    'address': addr,
                                    'name': name
                                }
                            except ValueError:
                                continue
                                
                    elif line.startswith('0x'):
                        # 符号定义行: "0x08000000 Reset_Handler"
                        parts = line.split()
                        if len(parts) >= 2:
                            try:
                                addr = int(parts[0], 16)
                                name = ' '.join(parts[1:])
                                # 过滤掉文件路径等非符号内容
                                if not name.endswith(('.o', '.a', '/')):
                                    self.map_symbols[name] = {
                                        'address': addr,
                                        'name': name,
                                        'size': 0  # 大小需要后续处理
                                    }
                            except ValueError:
                                continue
                                
        except Exception as e:
            print("Warning: Failed to parse MAP file:", str(e))
            
        # 计算符号大小
        self._calculate_symbol_sizes()
        
    def _calculate_symbol_sizes(self):
        """计算符号大小"""
        # 按地址排序所有符号
        sorted_symbols = sorted(
            self.map_symbols.items(),
            key=lambda x: x[1]['address']
        )
        
        # 计算每个符号的大小（使用下一个符号的地址）
        for i in range(len(sorted_symbols) - 1):
            curr_sym = sorted_symbols[i][1]
            next_sym = sorted_symbols[i + 1][1]
            curr_sym['size'] = next_sym['address'] - curr_sym['address']
            
        # 为最后一个符号设置一个默认大小
        if sorted_symbols:
            last_sym = sorted_symbols[-1][1]
            last_sym['size'] = 0x100  # 默认大小

    def find_symbol_by_address(self, addr):
        """查找地址对应的符号"""
        # 首先在ELF符号表中查找
        sym = self._find_function_in_axf(addr)
        if sym:
            return sym
            
        # 如果没找到，在MAP文件符号中查找
        return self._find_function_in_map(addr)
        
    def _find_function_in_map(self, addr):
        """从MAP文件符号中查找函数"""
        # 查找最近的符号
        closest_sym = None
        for sym_name, sym_info in self.map_symbols.items():
            sym_addr = sym_info['address']
            sym_size = sym_info['size']
            
            if sym_addr <= addr < (sym_addr + sym_size):
                if not closest_sym or sym_addr > closest_sym[1]['address']:
                    closest_sym = (sym_name, sym_info)
                    
        if closest_sym:
            # 转换为统一的格式
            return {
                'name': closest_sym[0],
                'addr': closest_sym[1]['address'],
                'size': closest_sym[1]['size']
            }
            
        return None
    def load_symbols(self):
        """加载符号表"""
        symtab = self.elf.get_section_by_name('.symtab')
        if symtab:
            for sym in symtab.iter_symbols():
                if sym['st_info']['type'] == 'STT_FUNC':
                    # 只保存函数符号
                    self.symbols[sym['st_value']] = {
                        'name': sym.name,
                        'addr': sym['st_value'],
                        'size': sym['st_size']
                    }
                    
    def load_line_numbers(self):
        """加载行号信息"""
        if not self.debug_info:
            return

        for CU in self.debug_info.iter_CUs():
            lineprog = self.debug_info.line_program_for_CU(CU)
            if not lineprog:
                continue

            for entry in lineprog.get_entries():
                state = entry.state
                if state is None:
                    continue

                if state.file and state.line:
                    file_name = lineprog['file_entry'][state.file - 1].name
                    if not isinstance(file_name, str):
                        file_name = file_name.decode('utf-8')
                    
                    # 保存地址到源码的映射
                    self.line_map[state.address] = {
                        'file': file_name,
                        'line': state.line,
                        'column': state.column if hasattr(state, 'column') else 0,
                        'is_stmt': state.is_stmt if hasattr(state, 'is_stmt') else False
                    }

    def get_source_location(self, addr):
        """获取源代码位置"""
        if not self.line_map:
            return None

        # 查找最接近但不超过addr的地址
        closest_addr = None
        for map_addr in self.line_map:
            if map_addr <= addr:
                if closest_addr is None or map_addr > closest_addr:
                    closest_addr = map_addr

        if closest_addr:
            return self.line_map[closest_addr]
        return None
        
    def find_function(self, addr):
        """查找函数信息"""
        # 首先在AXF符号表中查找
        func = self._find_function_in_axf(addr)
        if func:
            return func
            
        # 如果没找到，在MAP文件符号中查找
        return self._find_function_in_map(addr)
        
    def _find_function_in_axf(self, addr):
        """从AXF符号表中查找函数"""
        for base_addr, func in self.symbols.items():
            if base_addr <= addr < (base_addr + func['size']):
                return func
        return None
    def load_symbols(self):
        """加载符号表"""
        symtab = self.elf.get_section_by_name('.symtab')
        if symtab:
            for sym in symtab.iter_symbols():
                if sym['st_info']['type'] == 'STT_FUNC':
                    # 只保存函数符号
                    self.symbols[sym['st_value']] = {
                        'name': sym.name,
                        'addr': sym['st_value'],
                        'size': sym['st_size']
                    }

    def read_memory(self, addr, size):
        """读取内存数据"""
        ram_base = 0x20000000  # RAM起始地址
        if ram_base <= addr < ram_base + len(self.ram_data):
            offset = addr - ram_base
            return self.ram_data[offset:offset+size]
        return None
        
    def get_code_section(self):
        """获取代码段section"""
        # 首先尝试获取.text段
        section = self.elf.get_section_by_name('.text')
        if section is not None:
            return section
            
        # 如果没有.text段，查找具有可执行权限的段
        for section in self.elf.iter_sections():
            if section['sh_flags'] & 0x4:  # SHF_EXECINSTR
                return section
                
        return None

    def analyze_exception_frame(self, sp):
        """分析异常栈帧"""
        stack = self.read_memory(sp, 32)
        if not stack:
            return None
            
        try:
            return {
                'r0': struct.unpack('<I', stack[0:4])[0],
                'r1': struct.unpack('<I', stack[4:8])[0],
                'r2': struct.unpack('<I', stack[8:12])[0],
                'r3': struct.unpack('<I', stack[12:16])[0],
                'r12': struct.unpack('<I', stack[16:20])[0],
                'lr': struct.unpack('<I', stack[20:24])[0],
                'pc': struct.unpack('<I', stack[24:28])[0],
                'psr': struct.unpack('<I', stack[28:32])[0]
            }
        except:
            return None

    def unwind_stack(self, sp, max_depth=10):
        """展开调用栈"""
        frames = []
        current_sp = sp
        code_region = None
        
        # 获取代码区域范围
        for name, region in self.memory_regions.items():
            if name.upper() in ['FLASH', 'ROM', 'CODE']:
                code_region = region
                break

        # 如果找不到代码区域，使用默认范围
        if not code_region:
            code_region = {
                'start': 0x08000000,  # 典型的Flash起始地址
                'end': 0x08100000     # 假设1MB大小
            }

        depth = 0
        prev_sp = 0
        while depth < max_depth:
            # 检查SP有效性
            if not current_sp or current_sp % 4 != 0:  # ARM要求SP四字节对齐
                break
                
            if current_sp == prev_sp:  # 防止死循环
                break
            
            prev_sp = current_sp

            # 读取4字节作为可能的返回地址
            stack_data = self.read_memory(current_sp, 4)
            if not stack_data:
                break

            # 解析可能的返回地址
            try:
                ret_addr = struct.unpack('<I', stack_data)[0]
                
                # 检查是否是有效的代码地址
                if code_region['start'] <= ret_addr <= code_region['end']:
                    # 对于返回地址，需要考虑指令长度
                    # Thumb指令是2或4字节，所以我们往前看几个地址
                    possible_addrs = [ret_addr - 1, ret_addr - 2, ret_addr - 3, ret_addr - 4]
                    
                    for addr in possible_addrs:
                        func = self.find_symbol_by_address(addr)
                        if func:
                            # 确认这是一个调用指令的返回地址
                            code_section = self.get_code_section()
                            if code_section:
                                try:
                                    # 检查返回地址前的指令
                                    offset = addr - code_section['sh_addr']
                                    if 0 <= offset < code_section['sh_size']:
                                        code_bytes = code_section.data()[max(0, offset-4):offset]
                                        for insn in self.cs.disasm(code_bytes, addr-len(code_bytes)):
                                            # 检查是否是调用指令
                                            if insn.mnemonic in ['bl', 'blx', 'b']:
                                                frames.append({
                                                    'addr': ret_addr,
                                                    'func': func,
                                                    'sp': current_sp
                                                })
                                                depth += 1
                                                break
                                except:
                                    pass
                            break
                            
            except:
                pass

            # 移动到下一个可能的栈帧位置
            # 1. 首先尝试通过帧指针(R7或R11)
            # 2. 如果失败，则按4字节移动
            fp_data = self.read_memory(current_sp + 4, 4)  # 尝试读取下一个值作为帧指针
            if fp_data:
                try:
                    next_fp = struct.unpack('<I', fp_data)[0]
                    if (next_fp > current_sp and           # 帧指针应该增长
                        next_fp % 4 == 0 and              # 必须4字节对齐
                        next_fp < current_sp + 0x1000):   # 不能增长太多
                        current_sp = next_fp
                        continue
                except:
                    pass
            
            current_sp += 4

        return frames

    def disassemble_context(self, addr, size=32):
        """反汇编出错位置的上下文"""
        code_section = self.get_code_section()
        if not code_section:
            print("No code section found in ELF file")
            return

        try:
            offset = addr - code_section['sh_addr']
            if offset < 0 or offset >= code_section['sh_size']:
                print("Address 0x{:08X} is outside of code section".format(addr))
                return

            # 往前取一些指令
            start_offset = max(0, offset - size//2)
            code_bytes = code_section.data()[start_offset:offset + size//2]
            start_addr = code_section['sh_addr'] + start_offset

            print("\nDisassembly context around 0x{:08X}:".format(addr))
            print("-" * 60)
            
            for insn in self.cs.disasm(code_bytes, start_addr):
                prefix = "=>" if insn.address == addr else "  "
                print("{} 0x{:08X}: {:<8} {}".format(
                    prefix, insn.address, insn.mnemonic, insn.op_str))
            
            print("-" * 60)
            
        except Exception as e:
            print("Disassembly failed:", str(e))
    def parse_fault_registers(self):
        """分析故障寄存器以确定异常原因"""
        # 首先检查是否是HardFault
        if self.registers.get('IPSR', 0) == 3:  # HardFault
            fault_causes = ["Hard Fault Exception"]
            
            # 检查HFSR
            hfsr = self.registers.get('HFSR', 0)
            if hfsr:
                if hfsr & (1 << 30): 
                    fault_causes.append("Forced Hard Fault - Other configurable fault escalated to HardFault")
                if hfsr & (1 << 31): 
                    fault_causes.append("Vector Table Hard Fault")
                    
            # 检查CFSR
            cfsr = self.registers.get('CFSR', 0)
            if cfsr:
                mmfsr = cfsr & 0xFF
                bfsr = (cfsr >> 8) & 0xFF
                ufsr = (cfsr >> 16) & 0xFFFF
                
                # Memory Management Faults
                if mmfsr:
                    if mmfsr & (1 << 0): fault_causes.append("Instruction access violation")
                    if mmfsr & (1 << 1): fault_causes.append("Data access violation")
                    if mmfsr & (1 << 3): fault_causes.append("Unstacking error")
                    if mmfsr & (1 << 4): fault_causes.append("Stacking error")
                    if mmfsr & (1 << 7) and 'MMFAR' in self.registers:
                        fault_causes.append("Memory Management Fault at address 0x{:08X}".format(
                            self.registers['MMFAR']))
                
                # Bus Faults
                if bfsr:
                    if bfsr & (1 << 0): fault_causes.append("Instruction bus error")
                    if bfsr & (1 << 1): fault_causes.append("Precise data bus error")
                    if bfsr & (1 << 2): fault_causes.append("Imprecise data bus error")
                    if bfsr & (1 << 7) and 'BFAR' in self.registers:
                        fault_causes.append("Bus Fault at address 0x{:08X}".format(
                            self.registers['BFAR']))
                
                # Usage Faults
                if ufsr:
                    if ufsr & (1 << 0): fault_causes.append("Undefined instruction")
                    if ufsr & (1 << 1): fault_causes.append("Invalid state")
                    if ufsr & (1 << 2): fault_causes.append("Invalid PC load")
                    if ufsr & (1 << 3): fault_causes.append("No coprocessor")
                    if ufsr & (1 << 8): fault_causes.append("Unaligned access")
                    if ufsr & (1 << 9): fault_causes.append("Divide by zero")
                    
            # 检查死循环
            pc = self.registers.get('PC', 0)
            # 获取当前指令
            code_section = self.get_code_section()
            if code_section:
                try:
                    offset = pc - code_section['sh_addr']
                    code_bytes = code_section.data()[offset:offset+2]
                    insts = list(self.cs.disasm(code_bytes, pc))
                    if insts:
                        inst = insts[0]
                        if inst.mnemonic == 'b':  # 分支指令
                            target = int(inst.op_str.strip('#'), 16)
                            if target == pc:  # 跳转到自身
                                fault_causes.append("Infinite loop detected at PC=0x{:08X}".format(pc))
                except:
                    pass
                    
            return fault_causes
            
        return []
    def analyze_hardfault_location(self):
        """分析 hardfault 发生的具体位置"""
        # 1. 获取异常发生时的 PC 值
        pc = self.registers.get('PC', 0)
        lr = self.registers.get('LR', 0)
        sp = self.registers.get('SP', 0)
        
        # 2. 分析异常类型
        fault_type = "Unknown Fault"
        if 'IPSR' in self.registers:
            ipsr = self.registers['IPSR']
            if ipsr == 3:
                fault_type = "Hard Fault"
            elif ipsr == 4:
                fault_type = "Memory Management Fault"
            elif ipsr == 5:
                fault_type = "Bus Fault"
            elif ipsr == 6:
                fault_type = "Usage Fault"

        print("\n=== Fault Location Analysis ===")
        print("Fault Type: %s" % fault_type)
        
        # 3. 分析异常栈帧中的上下文
        exc_frame = self.analyze_exception_frame(sp)
        if exc_frame:
            fault_pc = exc_frame['pc']
            fault_lr = exc_frame['lr']
            print("Fault PC: 0x{0:08X}".format(fault_pc))
            print("Fault LR: 0x{0:08X}".format(fault_lr))
            
            # 检查是否是从异常返回时发生的故障
            if fault_lr & 0xF == 0xF:
                print("Fault occurred during exception return")
                
            # 获取异常发生时的实际代码位置
            actual_pc = fault_pc if fault_pc != 0xFFFFFFFD else fault_lr & ~1
        else:
            actual_pc = pc
        
        # 4. 获取源代码位置
        if hasattr(self, 'debug_info') and self.debug_info:
            location = self.get_source_location(actual_pc)
            if location:
                print("\nFault occurred at:")
                print("  File: %s" % location['file'])
                print("  Line: %d" % location['line'])
                # 尝试读取源代码行
                try:
                    with open(location['file'], 'r') as f:
                        lines = f.readlines()
                        fault_line = lines[location['line'] - 1].strip()
                        print("  Code: %s" % fault_line)
                except:
                    pass
        
        # 5. 获取功能上下文
        func = self.find_symbol_by_address(actual_pc)
        if func:
            print("\nFault occurred in function: %s" % func['name'])
            offset = actual_pc - func['addr']
            print("Offset from function start: +0x%X bytes" % offset)
        
        # 6. 反汇编故障位置的代码上下文
        print("\nDisassembly context:")
        self.disassemble_context(actual_pc)
        
        # 7. 分析故障原因
        cfsr = self.registers.get('CFSR', 0)
        if cfsr:
            self._analyze_fault_causes(cfsr)
        
        # 8. 检查访问违例地址
        if self.registers.get('CFSR', 0) & 0x80:  # MMFAR valid
            mmfar = self.registers.get('MMFAR', 0)
            if mmfar:
                print("\nInvalid memory access at address: 0x{0:08X}".format(mmfar))
                self._analyze_memory_region(mmfar)
        
        if self.registers.get('CFSR', 0) & 0x8000:  # BFAR valid
            bfar = self.registers.get('BFAR', 0)
            if bfar:
                print("Bus fault at address: 0x{0:08X}".format(bfar))
                self._analyze_memory_region(bfar)

    def _analyze_fault_causes(self, cfsr):
        """详细分析故障原因"""
        print("\nFault analysis:")
        
        # 解析 Memory Management Fault
        mmfsr = cfsr & 0xFF
        if mmfsr:
            print("Memory Management Fault:")
            if mmfsr & (1 << 0): print("  - Instruction access violation")
            if mmfsr & (1 << 1): print("  - Data access violation")
            if mmfsr & (1 << 2): print("  - During exception return")
            if mmfsr & (1 << 3): print("  - During unstack")
            if mmfsr & (1 << 4): print("  - During stack")
        
        # 解析 Bus Fault
        bfsr = (cfsr >> 8) & 0xFF
        if bfsr:
            print("Bus Fault:")
            if bfsr & (1 << 0): print("  - Instruction bus error")
            if bfsr & (1 << 1): print("  - Precise data bus error")
            if bfsr & (1 << 2): print("  - Imprecise data bus error")
            if bfsr & (1 << 3): print("  - During exception return")
            if bfsr & (1 << 4): print("  - During unstack")
            if bfsr & (1 << 5): print("  - During stack")
        
        # 解析 Usage Fault
        ufsr = (cfsr >> 16) & 0xFFFF
        if ufsr:
            print("Usage Fault:")
            if ufsr & (1 << 0): print("  - Undefined instruction")
            if ufsr & (1 << 1): print("  - Invalid state")
            if ufsr & (1 << 2): print("  - Invalid PC load")
            if ufsr & (1 << 3): print("  - No coprocessor")
            if ufsr & (1 << 8): print("  - Unaligned access")
            if ufsr & (1 << 9): print("  - Divide by zero")

    def _analyze_memory_region(self, addr):
        """分析内存访问区域"""
        # 检查该地址属于哪个内存区域
        for name, region in self.memory_regions.items():
            if region['start'] <= addr < region['end']:
                print("Address belongs to %s region" % name)
                offset = addr - region['start']
                print("Offset from region start: +0x%X" % offset)
                return
                
        # 如果找不到对应区域，检查是否访问了未映射区域
        print("Address is in unmapped memory region")
        
        # 检查是否接近某个有效区域
        closest_region = None
        min_distance = float('inf')
        for name, region in self.memory_regions.items():
            dist_start = abs(addr - region['start'])
            dist_end = abs(addr - region['end'])
            min_dist = min(dist_start, dist_end)
            if min_dist < min_distance:
                min_distance = min_dist
                closest_region = (name, region)
        
        if closest_region:
            print("Closest valid region is %s, distance: 0x%X bytes" % 
                (closest_region[0], min_distance))

    def call_addr2line(self, elf_file, address):
        # 获取当前 Python 脚本所在目录
        script_dir = os.path.dirname(os.path.realpath(__file__))
        addr2line_path = os.path.join(script_dir, 'addr2line')  # 假设 addr2line 和 Python 脚本在同一目录下
        # 构建命令行参数
        # command = ['addr2line', '-e', elf_file, address]
        command = [addr2line_path, '-e', elf_file, address]
        creationflags = 0
        try:
            # 调用 addr2line 并获取输出

            result = subprocess.run(command, capture_output=True, text=True, check=True, encoding='utf-8', creationflags = creationflags)

            if result.stdout:  # 确保有输出
                print("Address info:", result.stdout.strip(), "\n")
            else:
                print("\nNo output received from addr2line.")

        except subprocess.CalledProcessError as e:
            print(f"Error while running addr2line: {e}")
        except FileNotFoundError:
            print("addr2line not found. Make sure it's installed and in your PATH.")
        except UnicodeDecodeError as e:
            print(f"UnicodeDecodeError: {e} - Ensure the output encoding is handled correctly.")
    def analyze(self):
        """分析栈回溯"""
        try:
            # 1. 打印寄存器状态
            self.print_registers()
            
            # 2. 分析故障位置（新增）
            self.analyze_hardfault_location()
            
            # 3. 打印调用栈
            pc = self.registers.get('PC', 0)
            lr = self.registers.get('LR', 0)
            sp = self.registers.get('SP', 0)
            print("\n=== Call Stack ===")
            current_func = self.find_symbol_by_address(pc)
            if current_func:
                print("#0 {} (PC=0x{:08X})".format(current_func['name'], pc))
            addr = format(pc, '#08X')
            self.call_addr2line(self.AXF, addr)
            # 分析异常栈帧
            exc_frame = self.analyze_exception_frame(sp)
            if exc_frame:
                # 使用异常栈帧中保存的PC
                fault_pc = exc_frame['pc']
                fault_func = self.find_symbol_by_address(fault_pc)
                if fault_func:
                    print("#1 {} (PC=0x{:08X})".format(fault_func['name'], fault_pc))
                addr = format(fault_pc, '#08X')
                self.call_addr2line(self.AXF, addr)
            # 从各种可能的SP开始展开栈
            sp_candidates = [
                sp,                        # 当前SP
                exc_frame['r1'] if exc_frame else 0,  # R1可能保存了原始SP
                self.registers.get('R7', 0),  # ARM一般用R7作为帧指针
                self.registers.get('R11', 0)  # 有时也用R11作为帧指针
            ]
            
            frames_seen = set()  # 用于去重
            frame_num = 2
            
            for start_sp in sp_candidates:
                if not start_sp:
                    continue
                    
                frames = self.unwind_stack(start_sp)
                for frame in frames:
                    # 去重并打印
                    frame_key = (frame['func']['name'], frame['addr'])
                    if frame_key not in frames_seen:
                        frames_seen.add(frame_key)
                        print("#{} {} (return to 0x{:08X})".format(
                            frame_num, frame['func']['name'], frame['addr']))
                        addr = format(frame['addr'], '#08X')
                        self.call_addr2line(self.AXF, addr)
                        frame_num += 1
        except Exception as e:
            print("Error during analysis: {}".format(str(e)))
            import traceback
            traceback.print_exc()


def main():
    parser = argparse.ArgumentParser(description='ARM Stack Trace Tool')
    parser.add_argument('axf_file', help='path to AXF file')
    parser.add_argument('ram_dump', help='path to RAM dump file')
    parser.add_argument('--reg-dump', help='path to register dump file')
    parser.add_argument('--map-file', help='path to MAP file')
    
    args = parser.parse_args()
    
    try:
        tracer = StackTracer(args.axf_file, args.ram_dump, 
                           args.reg_dump, args.map_file)
        tracer.analyze()
    except Exception as e:
        print("Error:", str(e))
        import traceback
        traceback.print_exc()


if __name__ == '__main__':
    main()